#include <gtk/gtk.h>
#include "plist.h"

static GType column_types[PLIST_COLUMN_MAX]={
	G_TYPE_STRING,//title
	G_TYPE_STRING,//length
	G_TYPE_INT,//weight
	G_TYPE_INT,//song id
};

static int
plist_get_n_columns(GtkTreeModel *model)
{
	return PLIST_COLUMN_MAX;
}

static gboolean
plist_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter)
{
	return FALSE;
}

static GType
plist_get_column_type(GtkTreeModel *model, int column)
{
	return column_types[column];
}

static gboolean
plist_iter_nth_child(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, int index)
{
	gint plength = mpd_playlist_get_playlist_length(PLIST(model)->mpd);
	if(index >= plength)
		return FALSE;
	iter->user_data = (gpointer)index;
	return TRUE;
}

static gboolean
plist_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
{
	gint index = gtk_tree_path_get_indices(path)[0];
	return plist_iter_nth_child(model, iter, NULL, index);
}

static GtkTreePath*
plist_get_path(GtkTreeModel *model, GtkTreeIter *iter)
{
	return gtk_tree_path_new_from_indices((int)iter->user_data, -1);
}

static gboolean
plist_iter_next(GtkTreeModel *model, GtkTreeIter *iter)
{
	gint index = (int)iter->user_data + 1;
	return plist_iter_nth_child(model, iter, NULL, index);
}

static gint
plist_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter)
{
	if(iter != NULL)
		return 0;
	else
		return mpd_playlist_get_playlist_length(PLIST(model)->mpd);
}

static void
plist_get_value(GtkTreeModel *model, GtkTreeIter *iter, int column, GValue *value)
{
	PList *plist = PLIST(model);
	mpd_Song *song = mpd_playlist_get_song_from_pos(plist->mpd, (int)iter->user_data);

	switch(column){
	case PLIST_COLUMN_TITLE:
		g_value_init(value, G_TYPE_STRING);
		if(!song)
			break;
		if(song->title && song->artist){
			char *title = g_strdup_printf("%s - %s", song->artist, song->title);
			g_value_set_string(value, title);
			g_free(title);
		}else if(song->title)
			g_value_set_string(value, song->title);
		else
			g_value_set_string(value, g_basename(song->file));
		break;
	case PLIST_COLUMN_LENGTH:{
		g_value_init(value, G_TYPE_STRING);		
		char *length = g_strdup_printf("%d:%02d", song->time/60, song->time%60);
		g_value_set_string(value, length);
		g_free(length);
		break;
	}
	case PLIST_COLUMN_WEIGHT:{
		mpd_Song *csong = mpd_playlist_get_current_song(plist->mpd);
		g_value_init(value, G_TYPE_INT);
		if(csong && csong->pos == (int)iter->user_data){
			g_value_set_int(value, 800);
		}else{
			g_value_set_int(value, 400);
		}
		break;
	}
	case PLIST_COLUMN_SONG_ID:{
		g_value_init(value, G_TYPE_INT);
		g_value_set_int(value, plist_get_song_id(plist, iter));
	}
	}

	mpd_freeSong(song);
}

static gboolean 
plist_row_draggable(GtkTreeDragSource *drag_source, GtkTreePath *path)
{
	return TRUE;
}

static gboolean 
plist_drag_data_get(GtkTreeDragSource *drag_source, GtkTreePath *path, GtkSelectionData *selection)
{
	PList *plist = PLIST(drag_source);
	GtkTreeIter iter;

	if(!plist_get_iter(GTK_TREE_MODEL(plist), &iter, path))
		return FALSE;

	int songid = plist_get_song_id(plist, &iter);
	
	selection->target = gdk_atom_intern("move-song", TRUE);
	selection->format = sizeof(int);
	selection->data = g_memdup(&songid, sizeof(int));
	selection->length = sizeof(int);
	
	return TRUE;
}

static gboolean
plist_drag_data_received(GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection)
{
	GtkTreeIter iter;
	GtkTreeModel *model = GTK_TREE_MODEL(drag_dest);
	MpdObj *mpd = PLIST(model)->mpd;

	if(selection->target == gdk_atom_intern("splayer-playlist-song", TRUE)){
		int source_id = *((int*)selection->data);
		int dest_pos = 0;
		if(gtk_tree_model_get_iter(model, &iter, dest)){
			int dest_id = plist_get_song_id(PLIST(model), &iter);
			mpd_Song *dest_song = mpd_playlist_get_song(mpd, dest_id);
			dest_pos = dest_song->pos;
		}
		else{
			dest_pos = mpd_playlist_get_playlist_length(mpd) - 1;
		}
		mpd_Song *source_song = mpd_playlist_get_song(mpd, source_id);
		mpd_playlist_move_pos(PLIST(model)->mpd, source_song->pos, dest_pos);
		return TRUE;
	}else if(selection->target == gdk_atom_intern("splayer-db-path", TRUE)){
		char *path = (char*)selection->data;
		mpd_playlist_add(mpd, path);
		if(mpd_player_get_state(mpd) != MPD_PLAYER_PLAY)
			mpd_player_play(mpd);
		return TRUE;
	}else{
		printf("unexpected target:%s\n", gdk_atom_name(selection->target));
		return FALSE;
	}
}

static gboolean
plist_row_drop_possible(GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection)
{
	return TRUE;
}

static void 
plist_finalize(GObject *obj)
{
	g_dataset_destroy(obj);
}

static void
plist_class_init(PListClass *class)
{
	G_OBJECT_CLASS(class)->finalize = plist_finalize;
}

static void
plist_init(PList *plist)
{
}

static void
plist_drag_source_init(GtkTreeDragSourceIface *iface)
{
	iface->row_draggable = plist_row_draggable;
	iface->drag_data_get = plist_drag_data_get;
	iface->drag_data_delete = plist_row_draggable;
}

static void
plist_drag_dest_init(GtkTreeDragDestIface *iface)
{
	iface->drag_data_received = plist_drag_data_received;
	iface->row_drop_possible = plist_row_drop_possible;
}

static void 
plist_tree_model_init(GtkTreeModelIface *iface)
{
	iface->get_n_columns = plist_get_n_columns;
	iface->get_column_type = plist_get_column_type;
	iface->get_iter = plist_get_iter;
	iface->get_path = plist_get_path;
	iface->get_value = plist_get_value;
	iface->iter_next = plist_iter_next;
	iface->iter_has_child  = plist_iter_has_child;
	iface->iter_nth_child = plist_iter_nth_child;
	iface->iter_n_children = plist_iter_n_children;
}

int
plist_get_song_id(PList *plist, GtkTreeIter *iter)
{
	mpd_Song *song = mpd_playlist_get_song_from_pos(plist->mpd, (int)iter->user_data);
	if(song)
		return song->id;
	else
		return -1;
}

PList* 
plist_new(MpdObj* mpd)
{
	PList *result = g_object_new(TYPE_PLIST, NULL);
	result->mpd = mpd;
	return result;
}

G_DEFINE_TYPE_WITH_CODE(PList, plist, G_TYPE_OBJECT, 
						G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, plist_tree_model_init)
						G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_DRAG_SOURCE, plist_drag_source_init)
						G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_DRAG_DEST, plist_drag_dest_init));
